package com.uziot.bucket.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

/**
 * @author shidt
 * @version V1.0
 * @className UserService
 * @date 2021-02-24 11:50:19
 * @description 测试请求合并
 */

@Slf4j
@Service
public class UserService {

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 指定合并处理的方法名，这里单个请求方法和批处理方法的定义非常有考究，
     * 具体可以看一下这个注解的注释文档，方法只能接受一个参数，
     * 如果你需要传递多个参数，那么请将它们封装成一个类参数。
     * 然后批处理方法的参数必须是List类型的参数，泛型和单处理方法中的参数类型一致，
     * 例如示例代码中那样，单处理方法的参数为Long,
     * 批处理方法的参数为List<String>。
     * 另外单处理方法的方法体实际是不会执行的，返回null即可。
     *
     * @param id userId
     * @return username
     */
    @HystrixCollapser(
            // 合并作用域，默认是REQUEST，就是不会跨越多个请求会话的，
            // 只在当前用户请求中合并多次请求为批处理请求。这里改成GLOBAL，
            // 就是可以跨越request context，合并不同用户的请求为一次批处理请求。
            scope = com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL,
            batchMethod = "findByIds",
            collapserProperties = {
                    // 最大合并范围延时
                    @HystrixProperty(name = "timerDelayInMilliseconds", value = "1000"),
                    // 最大合并范围数量
                    @HystrixProperty(name = "maxRequestsInBatch", value = "3")
            }
    )
    public Future<String> findById(Long id) {
        log.info("findById : " + id);
        return null;
    }

    /**
     * 当请求达到指定时间，如果还没响应结果，予以执行熔断处理
     *
     * @param ids ids
     * @return 响应结果
     */
    @SuppressWarnings("unchecked")
    @HystrixCommand(commandProperties = @HystrixProperty(
            name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000"),
            fallbackMethod = "findByIdsFailback")
    public List<String> findByIds(List<Long> ids) {
        log.info("findByIds : " + ids);
        List<String> result = restTemplate.getForObject("http://hystrix-collapser-provider/users?ids={1}",
                List.class, StringUtils.join(ids, ","));
        assert result != null;
        log.info(result.toString());
        return result;
    }


    public List<String> findByIdsFailback(List<Long> ids) throws IOException {
        log.error("============用户信息查询:{},错误，熔断处理 fallback=============", ids);
        return Collections.emptyList();
    }
}
